package com.naiterui.ehp.bp.utils.beans;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.naiterui.ehp.bp.utils.exception.ConvertException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.ParameterizedTypeReference;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.Type;
import java.util.TimeZone;

/**
 * xml 工具类
 *
 * @author 王泽浩
 * @since 1.0.0
 */
@SuppressWarnings({"WeakerAccess", "unused"})
public class XmlMapper extends com.fasterxml.jackson.dataformat.xml.XmlMapper {

    /**
     * The constant MAPPER.
     */
    private static final XmlMapper MAPPER = new XmlMapper(Include.NON_EMPTY);
    private static final Logger LOGGER = LoggerFactory.getLogger(XmlMapper.class);
    private static final long serialVersionUID = 6619488081504006820L;

    /**
     * Instantiates a new Json MAPPER.
     */
    public XmlMapper() {
        this(Include.NON_EMPTY);
    }

    /**
     * Instantiates a new Json MAPPER.
     *
     * @param include the include
     */
    public XmlMapper(final Include include) {
        // 设置输出时包含属性的风格
        if (include != null) {
            this.setSerializationInclusion(include);
        }
        this.enable(SerializationFeature.INDENT_OUTPUT);
        // 设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性
        this.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        this.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
        // 设置时区 getTimeZone("GMT+8:00")
        this.setTimeZone(TimeZone.getDefault());
    }

    /**
     * 创建只输出非Null且非Empty(如List.isEmpty)的属性到Json字符串的Mapper,建议在外部接口中使用.
     *
     * @return the instance
     */
    @SuppressWarnings("SameReturnValue")
    private static XmlMapper getInstance() {
        return MAPPER;
    }

    public static String toXml(final Object object) {
        try {
            return XmlMapper.getInstance().writeValueAsString(object);
        } catch (JsonProcessingException e) {
            throw new ConvertException("对象转换XML失败", e);
        }
    }

    public static <T> T fromXml(final String xml, final Class<T> clazz) {
        try {
            return XmlMapper.getInstance().readValue(xml, clazz);
        } catch (IOException e) {
            throw new ConvertException(String.format("xml转对象失败 class:%s xml:%s", clazz.getName(), xml), e);
        }
    }

    public static <T> T fromXml(final String xml, final ParameterizedTypeReference<T> responseTypeReference) {
        Type type = responseTypeReference.getType();
        JavaType javaType = XmlMapper.getJavaType(type);
        return XmlMapper.fromXml(xml, javaType);
    }

    private static <T> T fromXml(final String xml, final JavaType javaType) {
        try {
            return XmlMapper.getInstance().readValue(xml, javaType);
        } catch (IOException e) {
            throw new ConvertException(String.format("xml转对象失败 javaType:%s xml:%s", javaType, xml), e);
        }
    }

    private static JavaType getJavaType(Type type) {
        TypeFactory typeFactory = XmlMapper.getInstance().getTypeFactory();
        return typeFactory.constructType(type);
    }

    public static <T> T toObject(String xml, Class<T> clazz) {
        try {
            Unmarshaller unmarshaller = JAXBContext.newInstance(clazz).createUnmarshaller();
            return (T) unmarshaller.unmarshal(new StringReader(xml));
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return null;
    }

    /*public static void main(String[] args) {
        String xml = "<Response service=\"RouteService\">\n" +
                "    <Head>ERR</Head>\n" +
                "    <ERROR code=\"4001\">系统发生数据错误或运行时异常</ERROR>\n" +
                "</Response>";


        StringReader xmlReader = new StringReader(xml);
        Response responseInfo = JAXB.unmarshal(xmlReader, Response.class);

//        RouteResponse response = fromXml(xml, RouteResponse.class);
        try {
            System.out.println(JsonMapper.toJson(responseInfo));
        } catch (Exception e) {

        }
    }*/
}
